home *** CD-ROM | disk | FTP | other *** search
- /**\
- |**| =====================================================================
- |**|
- |**| FILENAME
- |**| cubic library(Cubics2).c
- |**|
- |**| DESCRIPTION
- |**| This library is used by the TestCubics Quickdraw GX
- |**| sample program to create and use Cubics.
- |**|
- |**| COPYRIGHT
- |**| ©1992-1996 Copyright Apple Computer, Inc.
- |**| All rights reserved.
- |**|
- |**| Change History:
- |**|
- |**| 4/96 cnn Updated the header filename, description, and
- |**| copyright. Updated #includes to support changed
- |**| GX Library names. Changed fixed to Fixed. Changed
- |**| fract to Fract.
- |**|
- |**| =====================================================================
- \**/
-
- #include "FixMath.h"
-
- #include "GraphicsLibraries.h"
-
- /* this is the structyre for a single cubic -- from the library routines */
-
- /*
-
- typedef struct {
-
- gxPoint a;
- gxPoint b;
- gxPoint c;
- gxPoint d;
-
- } cubic;
-
- */
-
- typedef struct { /* this structure contains the cached cubic coefficients */
-
- Fixed ax, ay;
- Fixed bx, by;
- Fixed cx, cy;
- Fixed dx, dy;
-
- } xcubic;
-
- typedef struct { /* this structure is just for a gxPath */
-
- long contours;
- long count;
- long flags;
- gxPoint data[ 32 ];
-
- } SmallPath;
-
- /* internal prototypes */
-
- void CubicPath( SmallPath *pathptr, const cubic *cube, const long count );
-
- long CountQuadratics( const cubic * );
- long xCountQuadratics( const cubic * );
-
- gxPoint *ComputePoints( const cubic *cube, long count, gxPoint *storage );
-
- /* now we define some macros to calculate the inner products */
-
- #define xcube(xc,u) (FracMul(FracMul(FracMul((xc)->ax,(u))+(xc)->bx,(u))+(xc)->cx,(u))+(xc)->dx)
- #define ycube(xc,u) (FracMul(FracMul(FracMul((xc)->ay,(u))+(xc)->by,(u))+(xc)->cy,(u))+(xc)->dy)
-
- #define xcubeprime(xc,u) (FracMul(FracMul((3*(xc)->ax),(u))+(2*(xc)->bx),(u))+(xc)->cx)
- #define ycubeprime(xc,u) (FracMul(FracMul((3*(xc)->ay),(u))+(2*(xc)->by),(u))+(xc)->cy)
-
- /*--------------------------------------------------------------------------------
-
- NewCubic
-
- this routine makes a new cubic that has a tolerance of one pixel.
-
- cubic -> a pointer to the cubic
-
- --------------------------------------------------------------------------------*/
-
- gxShape NewCubic( const cubic *cube )
- {
- SmallPath pathrec;
-
- CubicPath( &pathrec, cube, xCountQuadratics( cube ) );
-
- /* now we are ready to create the gxPath */
-
- return( GXNewPaths((gxPaths *) &pathrec ) );
- }
-
- /*--------------------------------------------------------------------------------
-
- NewCubic2
-
- this routine is the same as above except that it has an optional
- parameter for determining how many points to include in a gxPath. the number
- determines the number of points 'off' the gxCurve which are needed.
-
- cubic -> a pointer to the cubic
-
- if you use this routine you should link it in with another which determines
- the number of points to be used. here is an example that depends on a global
- variable 'gerror' of type extended. also, see the 'optimized' example for
- 'xCountQuadratics' futher below.
-
- extended gerror = 1.0;
-
- long CountQuadratics( const cubic *cube )
- {
- long count;
- extended a, n;
-
- extended ax;
- extended ay;
-
- ax = Fix2X( - cube->a.x + 3 * cube->b.x - 3 * cube->c.x + cube->d.x );
- ay = Fix2X( - cube->a.y + 3 * cube->b.y - 3 * cube->c.y + cube->d.y );
-
- a = sqrt( ax * ax + ay * ay );
-
- n = power( ( a / ( 20.0 * gerror ) ), 1.0 / 3.0 );
-
- count = ceil( n );
-
- if( count <= 0 ) count += 1;
-
- return( count );
- }
-
- --------------------------------------------------------------------------------*/
-
- gxShape NewCubic2( const cubic *cube, const long count )
- {
- SmallPath pathrec;
-
- CubicPath( &pathrec, cube, ( count <= 0 ) ? CountQuadratics( cube ) : count );
-
- /* now we are ready to create the gxPath */
-
- return( GXNewPaths((gxPaths *) &pathrec ) );
- }
- /*--------------------------------------------------------------------------------
-
- CubicPath
-
- this routine fills in a data structure for a gxPath with the information
- of a cubic.
-
- pathptr -> a pointer to the gxPath
- cube -> the cubic
- count -> how many points to use
-
- --------------------------------------------------------------------------------*/
-
- void CubicPath( SmallPath *pathptr, const cubic *cube, const long count )
- {
- long *ptr;
-
- pathptr->contours = 1;
- pathptr->count = count + 2;
- pathptr->flags = 0x7FFFFFFF;
- pathptr->flags &= ~( (unsigned long) 0x80000000 >> ( count + 1 ) );
-
- ptr = (Fixed *) &pathptr->data[ 0 ];
-
- *ptr++ = cube->a.x;
- *ptr++ = cube->a.y;
-
- (void) ComputePoints( cube, count,(gxPoint *) ptr );
- }
- /*--------------------------------------------------------------------------------
-
- DrawCubic
-
- this routine draws a cubic with the given fill
-
- cube -> the cubic
- theFill -> how it should be filled
-
- --------------------------------------------------------------------------------*/
- void DrawCubic( const cubic *cube, gxShapeFill theFill )
- {
- gxShape sh = NewCubic( cube );
-
- if( theFill ) GXSetShapeFill( sh, theFill );
-
- GXDrawShape( sh );
- GXDisposeShape( sh );
- }
- /*--------------------------------------------------------------------------------
-
- SetCubic
-
- this routine sets the points inside of a gxPath to be those of the given
- cubic
-
- dest -> the gxShape to set
- cube -> the cubic
-
- --------------------------------------------------------------------------------*/
-
- void SetCubic( gxShape dest, const cubic *cube )
- {
- SmallPath pathrec;
-
- CubicPath( &pathrec, cube, xCountQuadratics( cube ) );
-
- GXSetPaths( dest, (gxPaths *) &pathrec );
- }
- /*--------------------------------------------------------------------------------
-
- ComputePoints
-
- this routine is where the cuadratic points get computed. note that this
- routine never fills in the last gxPoint in the code.
-
- cubic -> a pointer to the cubic
- count -> the number of points other than the two end ones
- that we need to generate.
- storage -> a place to put the points that are generated
-
- --------------------------------------------------------------------------------*/
- gxPoint *ComputePoints( const cubic *cube, long count, gxPoint *storage )
- {
- Fixed *ptr = (Fixed *) storage;
-
- /* this routine assumes that the first gxPoint has been moved in by the caller */
-
- if( 0 < count )
- {
- xcubic x;
-
- Fract u;
- Fract n;
-
- Fixed tempx1, tempy1;
- Fixed tempx2, tempy2;
-
- Fixed ntempx1, ntempy1;
- Fixed ntempx2, ntempy2;
-
- /* we now need to compute the coefficients for this cubic -- for efficient computation later */
-
- x.ax = -cube->a.x + 3 * cube->b.x - 3 * cube->c.x + cube->d.x;
- x.ay = -cube->a.y + 3 * cube->b.y - 3 * cube->c.y + cube->d.y;
- x.bx = 3 * cube->a.x - 6 * cube->b.x + 3 * cube->c.x;
- x.by = 3 * cube->a.y - 6 * cube->b.y + 3 * cube->c.y;
- x.cx = -3 * cube->a.x + 3 * cube->b.x;
- x.cy = -3 * cube->a.y + 3 * cube->b.y;
- x.dx = cube->a.x;
- x.dy = cube->a.y;
-
- n = FracDiv( 1, count ); /* LONGINT / LONGINT -> frac */
- u = n;
-
- /* store the first pair of values */
-
- tempx1 = cube->a.x >> 1;
- tempx2 = FracMul( x.cx, n ) >> 2;
-
- tempy1 = cube->a.y >> 1;
- tempy2 = FracMul( x.cy, n ) >> 2;
-
- /* we start here */
-
- for( ; 0 < count; --count )
- {
- /* compute the next gxPoint sequence */
-
- ntempx1 = xcube( &x, u ) >> 1;
- ntempx2 = FracMul( xcubeprime( &x, u ), n ) >> 2;
-
- ntempy1 = ycube( &x, u ) >> 1;
- ntempy2 = FracMul( ycubeprime( &x, u ), n ) >> 2;
-
- /* now store the gxPoint */
-
- *ptr++ = tempx1 + tempx2 + ntempx1 - ntempx2;
- *ptr++ = tempy1 + tempy2 + ntempy1 - ntempy2;
-
- tempx1 = ntempx1;
- tempx2 = ntempx2;
-
- tempy1 = ntempy1;
- tempy2 = ntempy2;
-
- u += n;
- }
-
- /* move in the last gxPoint of the cubic */
-
- *ptr++ = cube->d.x;
- *ptr++ = cube->d.y;
-
- }
- return((gxPoint *) ptr );
- }
-
- /*--------------------------------------------------------------------------------
-
- xCountQuadratics
-
- this routine calculates the number of cubics that would be needed
- to draw a with no more than a pixel error.
-
- cubic -> a pointer to the cubic
-
- --------------------------------------------------------------------------------*/
-
- long xCountQuadratics( const cubic *cube )
- {
- Fixed ax, ay;
-
- short temp;
- long count;
-
- /* first get the a vector components */
-
- ax = -cube->a.x + 3 * cube->b.x - 3 * cube->c.x + cube->d.x;
- ay = -cube->a.y + 3 * cube->b.y - 3 * cube->c.y + cube->d.y;
-
- /* now make sure that they are positive */
-
- if( ax < 0 ) ax = -ax;
- if( ay < 0 ) ay = -ay;
-
- /* now we need to pick the max one */
-
- ax = ( ay < ax ) ? ax : ay;
-
- /* we now divide by twenty and take the ceiling */
-
- /* NOTE: if you want the tolerance to be .5 then */
- /* divide ax by 10, .25 -> 5, etc */
-
- temp = ( FixDiv( ax, ff( 20 ) ) + 0xFFFF ) >> 16;
-
- /* this is a crude but fast and effective way of taking the cube root of */
- /* 'temp' which is between 0 and 27000 */
-
- if( temp <= 4096 )
- {
- if( temp <= 512 )
- {
- if( temp <= 64 )
- {
- if( temp <= 8 )
- {
- if( temp <= 1 )
- count = 1;
- else
- count = 2;
- }
- else
- {
- if( temp <= 27 )
- count = 3;
- else
- count = 4;
- }
- }
- else
- {
- if( temp <= 216 )
- {
- if( temp <= 125 )
- count = 5;
- else
- count = 6;
- }
- else
- {
- if( temp <= 343 )
- count = 7;
- else
- count = 8;
- }
- }
- }
- else
- {
- if( temp <= 1728 )
- {
- if( temp <= 1000 )
- {
- if( temp <= 729 )
- count = 9;
- else
- count = 10;
- }
- else
- {
- if( temp <= 1331 )
- count = 11;
- else
- count = 12;
- }
- }
- else
- {
- if( temp <= 2744 )
- {
- if( temp <= 2197 )
- count = 13;
- else
- count = 14;
- }
- else
- {
- if( temp <= 3375 )
- count = 15;
- else
- count = 16;
- }
- }
- }
- }
- else
- {
- if( temp <= 13824 )
- {
- if( temp <= 8000 )
- {
- if( temp <= 5832 )
- {
- if( temp <= 4913 )
- count = 17;
- else
- count = 18;
- }
- else
- {
- if( temp <= 6859 )
- count = 19;
- else
- count = 20;
- }
- }
- else
- {
- if( temp <= 10648 )
- {
- if( temp <= 9261 )
- count = 21;
- else
- count = 22;
- }
- else
- {
- if( temp <= 12167 )
- count = 23;
- else
- count = 24;
- }
- }
- }
- else
- {
- if( temp <= 21952 )
- {
- if( temp <= 17576 )
- {
- if( temp <= 15625 )
- count = 25;
- else
- count = 26;
- }
- else
- {
- if( temp <= 19683 )
- count = 27;
- else
- count = 28;
- }
- }
- else
- {
- if( temp <= 27000 )
- {
- if( temp <= 24389 )
- count = 29;
- else
- count = 30;
- }
- else
- {
- /* because our gxPath can only contain 32 -2 points we stop here */
-
- count = 30;
- }
- }
- }
- }
-
- return( count );
- }